package com.marketing.tenant.interceptor;

import com.marketing.tenant.annotation.RequirePermission;
import com.marketing.tenant.context.UserContext;
import com.marketing.tenant.feign.AuthServiceClient;
import com.marketing.tenant.util.JwtUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * 权限拦截器
 * 负责验证JWT token和权限校验
 */
@Component
public class AuthInterceptor implements HandlerInterceptor {

    private static final Logger logger = LoggerFactory.getLogger(AuthInterceptor.class);

    @Autowired
    private JwtUtil jwtUtil;
    
    @Autowired
    private AuthServiceClient authServiceClient;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        logger.debug("权限拦截器开始处理请求: {} {}", request.getMethod(), request.getRequestURI());

        // 如果不是方法处理器，直接放行
        if (!(handler instanceof HandlerMethod)) {
            return true;
        }

        HandlerMethod handlerMethod = (HandlerMethod) handler;
        
        // 检查方法上是否有权限注解
        RequirePermission methodAnnotation = handlerMethod.getMethodAnnotation(RequirePermission.class);
        RequirePermission classAnnotation = handlerMethod.getBeanType().getAnnotation(RequirePermission.class);
        
        // 如果方法和类都没有权限注解，直接放行
        if (methodAnnotation == null && classAnnotation == null) {
            logger.debug("接口无权限注解，直接放行: {} {}", request.getMethod(), request.getRequestURI());
            return true;
        }

        // 优先使用方法上的注解，如果没有则使用类上的注解
        RequirePermission annotation = methodAnnotation != null ? methodAnnotation : classAnnotation;

        try {
            // 获取token
            String token = getTokenFromRequest(request);
            if (!StringUtils.hasText(token)) {
                logger.warn("请求缺少token: {} {}", request.getMethod(), request.getRequestURI());
                sendUnauthorizedResponse(response, "缺少访问令牌");
                return false;
            }

            // 调用认证服务验证token并实现自动续期
            ResponseEntity<Map<String, Object>> authResponse = authServiceClient.verifyToken("Bearer " + token);
            Map<String, Object> userInfo = authResponse.getBody();
            
            if (userInfo == null || !(Boolean) userInfo.get("success")) {
                logger.warn("Token验证失败: {} {}", request.getMethod(), request.getRequestURI());
                sendUnauthorizedResponse(response, "访问令牌无效或已过期");
                return false;
            }

            // 从认证服务返回的用户信息中提取用户信息
            Long userId = ((Number) userInfo.get("userId")).longValue();
            String username = (String) userInfo.get("username");
            String role = (String) userInfo.get("role");
            List<String> roles = (List<String>) userInfo.get("roles");
            Set<String> permissions = Set.copyOf((List<String>) userInfo.get("permissionCodes"));

            logger.debug("用户信息提取成功: userId={}, username={}, role={}, roles={}, permissions={}", 
                    userId, username, role, roles, permissions);

            // 设置用户上下文
            UserContext.UserInfo existingUserInfo = UserContext.getUser();
            Long existingTenantId = existingUserInfo != null ? existingUserInfo.getTenantId() : null;
            
            UserContext.UserInfo userInfoContext = new UserContext.UserInfo(userId, username, role, roles, permissions, existingTenantId);
            UserContext.setUser(userInfoContext);

            // 如果只需要登录验证，不需要特定权限，直接放行
            if ((annotation.value().length == 0 && annotation.roles().length == 0) && annotation.requireLogin()) {
                logger.debug("只需要登录验证，验证通过，放行: {} {}", request.getMethod(), request.getRequestURI());
                return true;
            }

            // 检查权限
            if (annotation.value().length > 0) {
                boolean hasPermission = Arrays.stream(annotation.value())
                        .anyMatch(permission -> permissions.contains(permission));
                        
                if (!hasPermission) {
                    logger.warn("用户权限不足: {} {}, 需要权限: {}, 用户权限: {}", 
                            request.getMethod(), request.getRequestURI(), 
                            Arrays.toString(annotation.value()), permissions);
                    sendForbiddenResponse(response, "权限不足，需要权限: " + Arrays.toString(annotation.value()));
                    return false;
                }
            }

            // 检查角色
            if (annotation.roles().length > 0) {
                boolean hasRole = Arrays.stream(annotation.roles())
                        .anyMatch(roleCode -> roles.contains(roleCode));
                        
                if (!hasRole) {
                    logger.warn("用户角色不足: {} {}, 需要角色: {}, 用户角色: {}", 
                            request.getMethod(), request.getRequestURI(), 
                            Arrays.toString(annotation.roles()), roles);
                    sendForbiddenResponse(response, "角色不足，需要角色: " + Arrays.toString(annotation.roles()));
                    return false;
                }
            }

            logger.debug("权限验证通过，放行: {} {}", request.getMethod(), request.getRequestURI());
            return true;

        } catch (Exception e) {
            logger.error("权限验证过程中发生异常: {} {}, 异常: {}", 
                    request.getMethod(), request.getRequestURI(), e.getMessage(), e);
            sendUnauthorizedResponse(response, "权限验证失败");
            return false;
        }
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // 清除用户上下文
        UserContext.clear();
        logger.debug("清除用户上下文: {} {}", request.getMethod(), request.getRequestURI());
    }

    /**
     * 从请求中获取token
     */
    private String getTokenFromRequest(HttpServletRequest request) {
        // 从Header中获取token
        String bearerToken = request.getHeader("Authorization");
        if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
            return bearerToken.substring(7);
        }
        
        // 从参数中获取token（备用方案）
        String paramToken = request.getParameter("token");
        if (StringUtils.hasText(paramToken)) {
            return paramToken;
        }
        
        return null;
    }

    /**
     * 发送401未授权响应
     */
    private void sendUnauthorizedResponse(HttpServletResponse response, String message) throws Exception {
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        response.setContentType("application/json;charset=UTF-8");
        String jsonResponse = String.format(
                "{\"code\":401,\"message\":\"%s\",\"data\":null,\"timestamp\":%d}",
                message, System.currentTimeMillis()
        );
        response.getWriter().write(jsonResponse);
    }

    /**
     * 发送403禁止访问响应
     */
    private void sendForbiddenResponse(HttpServletResponse response, String message) throws Exception {
        response.setStatus(HttpServletResponse.SC_FORBIDDEN);
        response.setContentType("application/json;charset=UTF-8");
        String jsonResponse = String.format(
                "{\"code\":403,\"message\":\"%s\",\"data\":null,\"timestamp\":%d}",
                message, System.currentTimeMillis()
        );
        response.getWriter().write(jsonResponse);
    }
}